package br.com.upper.util;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import br.com.upper.entity.TestConfiguration;
import br.com.upper.entity.TestInstanceResult;
import br.com.upper.entity.Transaction;

public class LogProcessor {

	static LogRunnable logRunnable;
	
	public static void process(TestConfiguration configuration, String logResourcesPath, String logTransactionsPath) {
		ExecutorService pool = Executors.newSingleThreadExecutor();
		logRunnable = new LogRunnable(configuration, logResourcesPath, logTransactionsPath);
		pool.execute(logRunnable);
		pool.shutdown();
		//return logRunnable.result;
	}
	
}

class LogRunnable implements Runnable {
		
	boolean running;
	TestInstanceResult result;
	TestConfiguration configuration;
	String logResourcesPath;
	String logTransactionsPath;

	LogRunnable(TestConfiguration configuration, String logResourcesPath, String logTransactionsPath) {		
		this.configuration = configuration;
		this.logResourcesPath = logResourcesPath;
		this.logTransactionsPath = logTransactionsPath;
	}

	public void run() {
		try {
			running = true;
			FileInputStream fis = new FileInputStream(logTransactionsPath);
			InputStreamReader isr = new InputStreamReader(fis);
			BufferedReader br = new BufferedReader(isr);
		
			Map<String,Integer> execucoes = new HashMap<String,Integer>();
			for(Transaction t: this.configuration.getTransactions()) {
				execucoes.put(t.getNome(), 0);
			}
			
			Scanner scanner = new Scanner(br);
			String line = null;
			whileScanner: {
			while (scanner.hasNextLine()) {
				line = scanner.nextLine();
				for(Transaction transaction: this.configuration.getTransactions()) {
					if(line.indexOf(transaction.getNome()) > -1) {
						execucoes.put(transaction.getNome(), (execucoes.get(transaction.getNome()) + 1));
						Integer primeiraVirgula = line.indexOf(",");
						Long timeExecution = Long.valueOf(line.substring(primeiraVirgula + 1, line.indexOf(",",primeiraVirgula + 1)));
						if(timeExecution > transaction.getTimeExecution()) {
							
							Long timestamp = Long.valueOf(line.substring(0, primeiraVirgula));	
							
							Integer ultimaVirgula = line.lastIndexOf(",");
							Integer penultimaVirgula = line.lastIndexOf(",", ultimaVirgula - 1);	
							
							Integer totalThreads = Integer.valueOf(line.substring(penultimaVirgula + 1, ultimaVirgula));
							
							this.result = new TestInstanceResult();
							this.result.setData(new Date());
							this.result.setInstanceType(this.configuration.getInstanceType());
							this.result.setVolumeType(this.configuration.getVolumeType());
							this.result.setProvisionedIOPs(this.configuration.getProvisionedIOPS());						
							this.result.setMaxThreads(totalThreads);
							this.result.setTransactionExecTime(timeExecution);
							this.result.setTransactionMaxExecTime(transaction.getTimeExecution());
							this.result.setTransactionName(transaction.getNome());
							this.result.setTransactionTotalExecutions(execucoes.get(transaction.getNome()));
							
							this.loadServerMetrics(timestamp, timeExecution);
							break whileScanner;							
						}
						System.out.println(line);
					}
				}
				
			}
			}
			running = false;
			scanner.close();
			br.close();
			isr.close();
			fis.close();
			
		} catch (IOException ioe) {
			System.out.println("Processing Error" + ioe);
		}
	}
	
	private void loadServerMetrics(Long initTimestamp, Long timeExecution) throws IOException {
		FileInputStream fis = new FileInputStream(logResourcesPath);
		InputStreamReader isr = new InputStreamReader(fis);
		BufferedReader br = new BufferedReader(isr);
		
		Scanner scanner = new Scanner(br);
		String line = null;
		
		Double cpuMetric = null;
		Double memoryMetric = null;
		Double diskMetric = null;
		
		Long finalTimeStamp = initTimestamp + timeExecution;
		
		while (scanner.hasNextLine()) {
			line = scanner.nextLine();			
			Integer primeiraVirgula = line.indexOf(",");
			String timeStampStr = (line.substring(0, primeiraVirgula));
			
			if(!timeStampStr.equalsIgnoreCase("timeStamp")) {
				Long timestamp = Long.valueOf(timeStampStr);
				if(timestamp >= initTimestamp && timestamp <= finalTimeStamp) {
					if(line.indexOf("CPU") >= 0) {
						Double lineCpuMetric = Double.valueOf(line.substring(primeiraVirgula + 1, line.indexOf(",",primeiraVirgula + 1)));
						if(cpuMetric == null || lineCpuMetric > cpuMetric) {
							cpuMetric = lineCpuMetric;
						}
					} else if (line.indexOf("Memory") >= 0) {
						Double lineMemoryMetric = Double.valueOf(line.substring(primeiraVirgula + 1, line.indexOf(",",primeiraVirgula + 1)));
						if(memoryMetric == null || lineMemoryMetric > cpuMetric) {
							memoryMetric = lineMemoryMetric;
						}
					} else if (line.indexOf("Disks") >= 0) {
						Double lineDiskMetric = Double.valueOf(line.substring(primeiraVirgula + 1, line.indexOf(",",primeiraVirgula + 1)));
						if(diskMetric == null || lineDiskMetric > diskMetric) {
							diskMetric = lineDiskMetric;
						}
					}
				} else if (timestamp > finalTimeStamp) {
					break;
				}
			}
			

		}
		
		this.result.setCpuMetric(cpuMetric);
		this.result.setMemoryMetric(memoryMetric);
		this.result.setDiskMetric(diskMetric);
		running = false;
		scanner.close();
		br.close();
		isr.close();
		fis.close();
	}

}
